package com.pl.lc.user.service.impl;


import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.pl.lc.common.config.RabbitKeyConfig;
import com.pl.lc.common.config.RedisKeyConfig;
import com.pl.lc.common.config.SystemConfig;
import com.pl.lc.common.param.GrowthAdd;
import com.pl.lc.common.param.MqMsg;
import com.pl.lc.common.param.UserAdd;
import com.pl.lc.common.param.UserLogin;
import com.pl.lc.common.util.JwtUtil;
import com.pl.lc.common.vo.R;
import com.pl.lc.user.config.RabbitConfig;
import com.pl.lc.user.entity.Log;
import com.pl.lc.user.entity.SmsLog;
import com.pl.lc.user.entity.User;
import com.pl.lc.user.mapper.LogMapper;
import com.pl.lc.user.mapper.UserMapper;
import com.pl.lc.user.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 1.用户表 服务实现类
 * </p>
 *
 * @author pl
 * @since 2024-06-05
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private LogMapper logMapper;
    @Autowired
    private RabbitTemplate rabbitTemplate;


    /**
     * 1.判断参数是否为空
     * 2.判断验证码是否匹配 redis
     * 3.判断手机号是否重复  账号是否重复
     * 4.密码加密 插入user表
     * 5.记录用户日志
     * 6.删除注册验证码
     *
     * @param request
     * @param userAdd
     * @return
     */
    @Override
    public R register(HttpServletRequest request, UserAdd userAdd) {
        //1.判断参数是否为空
        if (userAdd == null || StringUtils.isAnyEmpty(userAdd.getPhone(), userAdd.getAccount(), userAdd.getPassword(), userAdd.getCode())) {
            return R.fail("参数为空");
        }
        // 2.判断验证码是否匹配 redis
        String redisCode = stringRedisTemplate.opsForValue().get(RedisKeyConfig.SMS_RCODE + userAdd.getPhone());
        if (!userAdd.getCode().equals(redisCode)) {
            return R.fail("验证码错误");
        }
        // 3.判断手机号是否重复  账号是否重复
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone", userAdd.getPhone());
        List<User> users = userMapper.selectList(queryWrapper);
        if (users != null && users.size() > 0) {
            return R.fail("手机号重复");
        }
        // 4.密码加密 插入user表
        User user = new User();
        user.setPhone(userAdd.getPhone())
                .setAccount(userAdd.getAccount())
                .setStatus(1)
                .setPassword(SecureUtil.md5(userAdd.getPassword()))
                .setCtime(new Date());
        int num = userMapper.insert(user);
        if (num <= 0) {
            return R.fail("注册失败");
        }
        // 5.记录用户日志
        Log log = new Log();
        log.setUserId(user.getId())
                .setMobile(user.getPhone())
                .setInfo(user.getPhone() + "用户注册")
                .setCtime(new Date())
                .setIp(request.getRemoteHost())
                .setType("用户注册");
        logMapper.insert(log);
        // 6.删除注册验证码
        redisTemplate.delete(RedisKeyConfig.SMS_RCODE + userAdd.getPhone());

        // 7.积分增加 发送消息
        MqMsg mqMsg = new MqMsg();
        //雪花算法
        mqMsg.setId(IdUtil.getSnowflakeNextId());
        mqMsg.setType(5);

        GrowthAdd growthAdd = new GrowthAdd();
        growthAdd.setUid(user.getId());
        growthAdd.setType("新用户注册");
        growthAdd.setGrowth(50);

        mqMsg.setMsg(growthAdd);
        //
        rabbitTemplate.convertAndSend("", RabbitKeyConfig.Q_USER_GROWTH, mqMsg);
        return R.ok("注册成功");
    }


    /**
     * 1.判断参数是否为空
     * 2.判断账户是存在，可用
     * 3.判断登录次数是否超过三次
     * 4.验证用户 密码
     * 5.生成token
     * 6.存储token
     * 7.记录登录日志
     * 8.返回token
     */
    @Override
    public R loginPass(UserLogin userLogin) {
        // 1.判断参数是否为空
        if (userLogin == null || StringUtils.isAnyEmpty(userLogin.getName(), userLogin.getPass())) {
            return R.fail("参数为空");
        }
        // 2.判断账户是存在，可用
        String account = userLogin.getName();
        String password = userLogin.getPass();
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("account", account);
        QueryWrapper<User> or = queryWrapper.or();
        or.eq("password", password);
        List<User> userList = userMapper.selectList(queryWrapper);
        if (userList == null || userList.size() <= 0) {
            return R.fail("用户不存在");
        }
        // 3.判断登录次数是否超过三次
        User user = userList.get(0);
        Set<String> keys = redisTemplate.keys(RedisKeyConfig.LOGIN_UID_TOKEN + user.getId() + "*");
        if (keys != null && keys.size() >= 3) {
            return R.fail("登录次数超过三次");
        }
        // 4.验证用户密码
        if (!user.getPassword().equals(SecureUtil.md5(password))) {
            return R.fail("密码错误");
        }
        // 5.生成token
        String token = JwtUtil.createJwt(user.getId(), account, user.getPhone());
        // 6.存储token
        //  key   id + token       可以计算该id登录的次数  ==》  key:lc:uid:用户id:令牌   value 时间戳
        //  key   token         记录该token 对应的用户信息 ====> key:lc:token:令牌     value 用户对象信息
        stringRedisTemplate.opsForValue().set(RedisKeyConfig.LOGIN_UID_TOKEN + user.getId() + ":" + token, "", 12 * 60 * 60, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(RedisKeyConfig.LOGIN_TOKEN + token, user, 12 * 60 * 60, TimeUnit.SECONDS);
        // 7.记录登录日志
        Log log = new Log();
        log.setUserId(user.getId())
                .setMobile(user.getPhone())
                .setInfo(user.getPhone() + "用户登录")
                .setCtime(new Date())
                .setType("用户登录");
        logMapper.insert(log);

        // 7.积分增加 发送消息
        MqMsg mqMsg = new MqMsg();
        //雪花算法
        mqMsg.setId(IdUtil.getSnowflakeNextId());
        mqMsg.setType(5);
        GrowthAdd growthAdd = new GrowthAdd();
        // if (isFirstLoginToday(user.getId())) {
        //
        //     // 设置登录标记，这里保持简单，但已避免硬编码的方式
        //     redisTemplate.opsForValue().set(RedisKeyConfig.LOGIN_TOKEN + token, "1");
        //     // 记录用户今日已登录，下次登录时不再加分
        //     // 设置键的过期时间，考虑时区问题，使用ZonedDateTime
        //     ZonedDateTime todayEnd = ZonedDateTime.now().with(LocalTime.MAX);
        //     ZonedDateTime tomorrowStart = todayEnd.plusDays(1).with(LocalTime.MIN);
        //     redisTemplate.expireAt(RedisKeyConfig.LOGIN_TOKEN + token, tomorrowStart.toInstant());
        //     //
        // }else {
        //     growthAdd.setUid(user.getId());
        //     growthAdd.setType("用户每日非首次登录");
        //     growthAdd.setGrowth(0);
        // }
        growthAdd.setUid(user.getId());
        growthAdd.setType("用户每日首次登录");
        growthAdd.setGrowth(2);
        mqMsg.setMsg(growthAdd);
        System.out.println(growthAdd);
        rabbitTemplate.convertAndSend("", RabbitKeyConfig.Q_USER_GROWTH, mqMsg);

        // 8.返回token
        return R.ok(token);
    }
    /**
     * 检查用户是否是今日首次登录
     * @param id 用户ID
     * @return 如果是首次登录返回true，否则返回false
     */
    private boolean isFirstLoginToday(Integer id) {
        // 使用Key查询登陆次数
        Set<String> keys = redisTemplate.keys(RedisKeyConfig.LOGIN_UID_TOKEN + id + "*");

        // 直接使用isEmpty()方法检查集合是否为空
        if (keys.size()==0)
        return true;
        return false;
    }

    /**
     * 记录用户今日已登录
     * @param token 用户token，用于登录标记
     */
    private void recordLoginToday( String token) {





    }

    /**
     * 手机号登录
     * 3.判断  数据是否为空
     * 4.判断账号是否存在  是否可用
     * 5.判断手机号 和 验证码 是否对应
     * 6  判断当前手机号的在线次数是否超过 三次
     * 7.生成token   一个字符串 包含用户信息（id,phone,account）
     * <token,用户信息>        记录用户登录的token
     * <phone+token,“xxx”>       登录一次记录一次             账户只可以 三个账号在线
     * 8.记录用户日志 登录
     * 9.返回token
     */

    @Override
    public R loginCode(UserLogin userLogin) {
        // 1.判断参数是否为空
        if (userLogin == null || StringUtils.isAnyEmpty(userLogin.getName(), userLogin.getPass())) {
            return R.fail("参数为空");
        }
        //判断手机号是否存在  是否可用
        String phone = userLogin.getName();
        String code = userLogin.getPass();
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("phone", phone);
        List<User> users = userMapper.selectList(queryWrapper);
        if (users == null || users.size() <= 0) {
            return R.fail("手机号不存在");
        }
        //判断当前手机号的在线次数是否超过 三次
        User user = users.get(0);
        Set<String> keys = redisTemplate.keys(RedisKeyConfig.LOGIN_UID_TOKEN + user.getId() + "*");
        if (keys == null && keys.size() > 3) {
            return R.fail("登录次数超过三次");
        }
        // 验证手机号验证码
        String loginCode = stringRedisTemplate.opsForValue().get(RedisKeyConfig.SMS_LCODE + phone);
        if (!code.equals(loginCode)) {
            return R.fail("验证码错误");
        }
        // 生成token
        String token = JwtUtil.createJwt(user.getId(), phone, user.getPhone());
        // 6.存储token
        //  key   id + token       可以计算该id登录的次数  ==》  key:lc:uid:用户id:令牌   value 时间戳
        //  key   token         记录该token 对应的用户信息 ====> key:lc:token:令牌     value 用户对象信息
        stringRedisTemplate.opsForValue().set(RedisKeyConfig.LOGIN_UID_TOKEN + user.getId() + ":" + token, "", 12 * 60 * 60, TimeUnit.SECONDS);
        redisTemplate.opsForValue().set(RedisKeyConfig.LOGIN_TOKEN + token, user, 12 * 60 * 60, TimeUnit.SECONDS);
        // 7.记录登录日志
        Log log = new Log();
        log.setUserId(user.getId())
                .setMobile(user.getPhone())
                .setInfo(user.getPhone() + "手机号登录")
                .setCtime(new Date())
                .setType("手机号登录");
        logMapper.insert(log);
        // 8.返回token
        return R.ok(token);
    }

    /**
     * 退出登录业务
     *
     * @param
     * @return
     */
    @Override
    public R logout(String token) {
        //获取用户信息
        User user = (User) redisTemplate.opsForValue().get(RedisKeyConfig.LOGIN_TOKEN + token);
        //删除redis中存储的token
        redisTemplate.delete(RedisKeyConfig.LOGIN_TOKEN + token);
        //删除redis中存储的登陆次数
        stringRedisTemplate.delete(RedisKeyConfig.LOGIN_UID_TOKEN + user.getId() + ":" + token);
        return R.ok("退出登录成功");
    }

}
